﻿/******************************************************************************
 * This file is part of libemb.
 *
 * libemb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libemb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libemb.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Project: Embedme
 * Author : FergusZeng
 * Email  : cblock@126.com
 * git	  : https://git.oschina.net/cblock/embedme
 * Copyright 2014~2017 @ ShenZhen ,China
*******************************************************************************/
#include "Socket.h"
#include "Tracer.h"

#include <arpa/inet.h>
#include <netdb.h>

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include <sys/ioctl.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>

#include <iostream>

Socket::Socket():
m_peerAddr(""),
m_peerPort(-1),
m_sockfd(-1)
{
}
Socket::~Socket()
{
}

bool Socket::open(const char *device, int ioMode)
{
    return this->open();
}

/**
 *  \brief  关闭socket
 *  \param  void
 *  \return 成功返回true,失败返回false
 *  \note   none
 */
bool Socket::close()
{
    if (m_sockfd >= 0)
    {
        ::close(m_sockfd);
    }
    //TRACE_YELLOW("socket close(%d)\n",m_sockfd);
    m_sockfd = -1;
    return true;
}
/**
 *  \brief  socket查看缓冲区数据
 *  \param  buf 接收缓存
 *  \param  len 缓存大小
 *  \param  timeoutMs 超时时间,-1:阻塞,0:立即返回,>0:超时时间ms
 *  \return 成功返回查看的数据长度,失败返回STATUS_ERROR
 *  \note   none
 */
int Socket::peekData(char * buf, int len,int timeoutMs)
{
    int ret;
    if (NULL == buf || len <= 0)
    {
        TRACE_ERR_CLASS("param error.\n");
        return STATUS_ERROR;
    }
	
	if (m_sockfd<0)
	{
		TRACE_ERR_CLASS("socket not open.\n");
		return STATUS_ERROR;
	}

    struct timeval tv,*ptv;
    fd_set readfds;
    if (timeoutMs<0)
    {
        ptv=NULL;
    }
    else
    {
        ptv = &tv;
        tv.tv_sec = timeoutMs/1000;
        tv.tv_usec = (timeoutMs%1000)*1000;
    }
    FD_ZERO(&readfds);
    FD_SET(m_sockfd, &readfds);
    ret = select(m_sockfd + 1, &readfds, NULL, NULL, ptv);
    if (0 == ret)
    {
        //TRACE_INFO_CLASS("recv timeout.\n");
        return STATUS_ERROR;
    }
    else if ((ret < 0) && (errno != EINTR))
    {
        TRACE_ERR_CLASS("select error:%s\n",ERROR_STRING);
        return STATUS_ERROR;
    }
    /* 检查fd是否可读 */
    if (!FD_ISSET(m_sockfd, &readfds))
    {
        TRACE_ERR_CLASS("readfds error\n");
        return STATUS_ERROR;
    }

    int recvLen = recv(m_sockfd, buf, len, MSG_PEEK);
    if (recvLen < 0)
    {
        if (errno == ECONNABORTED)
        {
            TRACE_ERR_CLASS("socket peek error:%s\n", ERROR_STRING);
            return 0;
        }
        else if (errno != EAGAIN)
        {
            TRACE_ERR_CLASS("sockfd(%d) peek error:%s\n", m_sockfd, ERROR_STRING);
            return STATUS_ERROR;
        }
    }
    return recvLen;
}
/**
 *  \brief  socket接收数据
 *  \param  buf 接收缓存
 *  \param  len 缓存大小
 *  \param  timeoutMs 超时时间,-1:阻塞,0:立即返回,>0:超时时间ms
 *  \return 成功返回接收的数据长度,失败返回STATUS_ERROR
 *  \note   none
 */
int Socket::readData(char * buf, int len,int timeoutMs)
{
    int ret;
    if (NULL == buf || len <= 0)
    {
        TRACE_ERR_CLASS("param error.\n");
        return STATUS_ERROR;
    }
	
	if (m_sockfd<0)
	{
		TRACE_ERR_CLASS("socket not open.\n");
		return STATUS_ERROR;
	}

    struct timeval tv,*ptv;
    fd_set readfds;
    if (timeoutMs<0)
    {
        ptv=NULL;
    }
    else
    {
        ptv = &tv;
        tv.tv_sec = timeoutMs/1000;
        tv.tv_usec = (timeoutMs%1000)*1000;
    }
    FD_ZERO(&readfds);
    FD_SET(m_sockfd, &readfds);
    ret = select(m_sockfd + 1, &readfds, NULL, NULL, ptv);
    if (0 == ret)
    {
        //TRACE_INFO_CLASS("recv timeout.\n");
        return STATUS_ERROR;
    }
    else if ((ret < 0) && (errno != EINTR))
    {
        TRACE_ERR_CLASS("select error:%s\n",ERROR_STRING);
        return STATUS_ERROR;
    }
    /* 检查fd是否可读 */
    if (!FD_ISSET(m_sockfd, &readfds))
    {
        TRACE_ERR_CLASS("readfds error\n");
        return STATUS_ERROR;
    }

    //int recvLen = read(m_sockfd, buf, len);
    int recvLen = recv(m_sockfd, buf, len, 0);
    if (recvLen < 0)
    {
        if (errno == ECONNABORTED)
        {
            TRACE_ERR_CLASS("socket read error:%s\n", ERROR_STRING);
            return 0;
        }
        else if (errno != EAGAIN)
        {
            TRACE_ERR_CLASS("sockfd(%d) read error:%s\n", m_sockfd, ERROR_STRING);
            return STATUS_ERROR;
        }
    }
    return recvLen;
}
/**
 *  \brief  socket发送数据
 *  \param  data 发送数据缓存
 *  \param  len 缓存大小
 *  \param  timeoutMs 超时时间,-1:阻塞,0:立即返回,>0:超时时间ms
 *  \return 成功返回发送的数据长度,失败返回STATUS_ERROR
 *  \note   none
 */
int Socket::writeData(const char* data, int len,int timeoutMs)
{
    int ret;
    if ((NULL == data) || len<=0)
    {
        TRACE_ERR_CLASS("param error.\n");
        return STATUS_ERROR;
    }
	
	if (m_sockfd<0)
	{
		TRACE_ERR_CLASS("socket not open.\n");
		return STATUS_ERROR;
	}

    struct timeval tv,*ptv;
    fd_set writefds;
    if (timeoutMs<0)
    {
        ptv=NULL;
    }
    else
    {
        ptv = &tv;
        tv.tv_sec = timeoutMs/1000;
        tv.tv_usec = (timeoutMs%1000)*1000;
    }
    FD_ZERO(&writefds);
    FD_SET(m_sockfd, &writefds);
    ret = select(m_sockfd + 1, NULL, &writefds, NULL, ptv);
    if (0==ret)
    {
        //TRACE_ERR_CLASS("send timeout.\n");
        return STATUS_ERROR;
    }
	else if(ret<0)
	{
		TRACE_ERR_CLASS("select error:%s\n",ERROR_STRING);
        return STATUS_ERROR;
	}
	
    /* 检查fd是否可写 */
    if (!FD_ISSET(m_sockfd, &writefds))
    {
        TRACE_ERR_CLASS("writefds error\n");
        return STATUS_ERROR;
    }

    /* 防止在socket关闭后,write会产生SIGPIPE信号导致进程退出 */
    signal(SIGPIPE, SIG_IGN);
    //int sndLen = write(m_sockfd, data, len);
    int sndLen = send(m_sockfd, data, len, 0);
    if (sndLen < 0)
    {
        TRACE_ERR_CLASS("sockfd(%d) write error:%s\n", m_sockfd, ERROR_STRING);
        return STATUS_ERROR;
    }
    return sndLen;
}
/**
 *  \brief  设置socket类型
 *  \param  socketType SOCKET_TYPE_E
 *  \return 成功返回STATUS_OK,失败返回STATUS_ERROR
 *  \note   none
 */
int Socket::setAttribute(int attr, int value)
{
	int level;	/* SOL_SOCKET,IPPROTO_TCP,IPPROTO_IP,IPPROTO_IPV6 */
	int option;
    int optionVal;
	int ret;
    switch(attr)
    {
        case SOCKET_ATTR_CASTTYPE:
        	if (value==SOCKET_BROADCAST)
        	{
        		level = SOL_SOCKET;
        		option = SO_BROADCAST;
        		optionVal = 1;
        	}
        	else if(value==SOCKET_MULTICAST)
        	{

        	}
        	else if(value==SOCKET_GROUPCAST)
        	{

        	}
        	else
        	{
        		TRACE_ERR_CLASS("Unsupport socket type:%d\n",value);
        		return STATUS_ERROR;
        	}
            break;
        case SOCKET_ATTR_RCVBUF:
        {   
            level = SOL_SOCKET;
    		option = SO_RCVBUF;
    		optionVal = value;
            break;
        }
        case SOCKET_ATTR_SNDBUF:
        {   
            level = SOL_SOCKET;
    		option = SO_SNDBUF;
    		optionVal = value;
            break;
        }
        default:
            TRACE_ERR_CLASS("Unsupport socket attr:%d\n",attr);
        	return STATUS_ERROR;
    }
    ret=setsockopt(m_sockfd, level, option, &optionVal, sizeof(optionVal));
	if (ret<0)
	{
		return STATUS_ERROR;
	}
	return STATUS_OK;
}

int Socket::getAttribute(int attr)
{
    int level;	/* SOL_SOCKET,IPPROTO_TCP,IPPROTO_IP,IPPROTO_IPV6 */
	int option;
    int optionVal;
    int optionLen;
	int ret;
    switch(attr)
    {
        case SOCKET_ATTR_RCVBUF:
        {   
            level = SOL_SOCKET;
    		option = SO_RCVBUF;
            break;
        }
        case SOCKET_ATTR_SNDBUF:
        {   
            level = SOL_SOCKET;
    		option = SO_SNDBUF;
            break;
        }
        default:
            TRACE_ERR_CLASS("Unsupport socket attr:%d\n",attr);
        	return STATUS_ERROR;
    }
    ret=getsockopt(m_sockfd, level, option, &optionVal, (socklen_t*)&optionLen);
	if (ret<0)
	{
		return STATUS_ERROR;
	}
    return optionVal;
}

bool Socket::isAlive()
{
    return (m_sockfd<0)?false:true;
}

bool Socket::open()
{
    return false;
}
/**
 *  \brief  绑定socket到指定IP地址的端口上
 *  \param  localPort 要绑定的端口
 *  \param  localAddr 绑定的IP地址,不指定则为默认本机任意地址
 *  \return 成功返回true,失败返回false
 *  \note   none
 */
bool Socket::bind(uint16 localPort, std::string localAddr)
{
    int ret = -1;
    if (m_sockfd < 0)
    {
        TRACE_ERR_CLASS("socket is not open\n");
        return false;
    }
	
    /*为TCP链接设置IP和端口等信息*/
    bzero(&m_localSockAddr, sizeof(m_localSockAddr));
    m_localSockAddr.sin_family = AF_INET;
    m_localSockAddr.sin_port = htons(localPort);

    /* 如果本机ip地址没指定,则设置本机任意地址 */
    if (localAddr.empty())
    {
        m_localSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    }
    else
    {
        m_localSockAddr.sin_addr.s_addr = inet_addr(localAddr.c_str());
    }
    /*地址与socket绑定bind*/
    ret = ::bind(m_sockfd, (struct sockaddr *)&m_localSockAddr, sizeof(m_localSockAddr));
    if (ret < 0)
    {
        TRACE_ERR_CLASS("bind(%s:%d) error:%s.\n", inet_ntoa(m_localSockAddr.sin_addr), 
						localPort, ERROR_STRING);
        return false;
    }

    TRACE_REL_CLASS("bind ok %s:%d\n", inet_ntoa(m_localSockAddr.sin_addr), localPort);

    return true;
}

/**
 *  \brief  检查socket是否已打开
 *  \param  void
 *  \return 打开返回true,关闭返回false
 *  \note   none
 */
bool Socket::connectToHost(uint16 peerPort, std::string peerAddr)
{
    if (peerAddr.empty()||peerPort<=0) 
    {
        TRACE_ERR_CLASS("Host is invalid,addr:%s,port:%d.\n",peerAddr.c_str(),peerPort);
        return false;
    }
    m_peerPort = peerPort;
    m_peerAddr = peerAddr;
	return true;
}


UdpSocket::UdpSocket()
{
}
UdpSocket::~UdpSocket()
{
}
/**
 *  \brief  打开UDP socket
 *  \param  void
 *  \return 成功返回true,失败返回false
 *  \note   none
 */
bool UdpSocket::open()
{
    if (m_sockfd < 0)
    {
        m_sockfd = socket(PF_INET, SOCK_DGRAM, 0);
        if (m_sockfd < 0)
        {
            TRACE_ERR_CLASS("open socket error:%s\n", ERROR_STRING);
            return false;
        }
    }
    return true;
}

/**
 *  \brief  关闭UDP socket
 *  \param  void
 *  \return 成功返回true,失败返回false
 *  \note   none
 */
bool UdpSocket::close()
{
    return Socket::close();
}

/**
 *  \brief  UDP socket接收数据
 *  \param  buf 接收缓存
 *  \param  len 缓存大小
 *  \param  timeoutMs 超时时间,-1:阻塞,0:立即返回,>0:超时时间ms
 *  \param  peerAddr 对端IP地址
 *  \param  peerPort 对端端口
 *  \return 成功返回接收的数据长度,失败返回STATUS_ERROR
 *  \note   none
 */
int UdpSocket::readData(char * buf, int len, int timeoutMs)
{
    int ret;
    if (NULL==buf || len<=0)
    {
        TRACE_ERR_CLASS("param error.\n");
        return STATUS_ERROR;
    }
	if (m_sockfd<0)
	{
		TRACE_ERR_CLASS("socket not open.\n");
		return STATUS_ERROR;
	}

    fd_set readfds;
    FD_ZERO(&readfds);
    FD_SET(m_sockfd, &readfds);
    
    struct timeval tv,*ptv;
    if (timeoutMs<0)
    {
        ptv=NULL;
    }
    else
    {
        tv.tv_sec = timeoutMs/1000;
        tv.tv_usec = (timeoutMs%1000)*1000;
        ptv = &tv;
    }
    
    ret = select(m_sockfd + 1, &readfds, NULL, NULL, ptv);
    if (0 == ret)
    {
        //TRACE_ERR_CLASS("recv timeout\n");
        return STATUS_ERROR;
    }
    else if ((ret < 0) && (errno != EINTR))
    {
        TRACE_ERR_CLASS("select error:%s.\n",ERROR_STRING);
        return STATUS_ERROR;
    }
    /* 检查fd是否可读 */
    if (!FD_ISSET(m_sockfd, &readfds))
    {
        TRACE_ERR_CLASS("readfds error.\n");
        return STATUS_ERROR;
    }

    struct sockaddr_in cliSockAddr;
    socklen_t addLen = sizeof(cliSockAddr);
    int recvLen = recvfrom(m_sockfd, buf, len, 0,
                              (struct sockaddr *)&cliSockAddr,
                              &addLen);
    if (recvLen < 0)
    {
        if (errno != EAGAIN)
        {
            TRACE_ERR_CLASS("sockfd(%d) read error:%s\n",m_sockfd, ERROR_STRING);
            return STATUS_ERROR;
        }
    }
    m_peerAddr = inet_ntoa(cliSockAddr.sin_addr);
    m_peerPort = ntohs(cliSockAddr.sin_port);
    //TRACE_DBG_CLASS("UDP recvfrom(%s:%d)\n",m_peerAddr.c_str(),m_peerPort);
    return recvLen;
}

/**
 *  \brief  UDP socket发送数据
 *  \param  data 发送数据缓存
 *  \param  len 缓存大小
 *  \param  timeoutMs 超时时间,-1:阻塞,0:立即返回,>0:超时时间ms
 *  \param  peerAddr 对端IP地址
 *  \param  peerPort 对端端口
 *  \return 成功返回发送的数据长度,失败返回STATUS_ERROR
 *  \note   none
 */
int UdpSocket::writeData(const char * data, int len, int timeoutMs)
{
    int ret;
    if (m_peerAddr == "" || m_peerPort == 0)
    {
        TRACE_ERR_CLASS("peerAddr:%s,peerPort:%d.\n",m_peerAddr.c_str(),m_peerPort);
        return STATUS_ERROR;
    }
    if (NULL == data || len<=0)
    {
        TRACE_ERR_CLASS("param error.\n");
        return STATUS_ERROR;
    }
	
	if (m_sockfd<0)
	{
		TRACE_ERR_CLASS("socket not open.\n");
		return STATUS_ERROR;
	}

    fd_set writefds;
    FD_ZERO(&writefds);
    FD_SET(m_sockfd, &writefds);

    struct timeval tv,*ptv;
    if (timeoutMs<0)
    {
        ptv=NULL;
    }
    else
    {
        tv.tv_sec = timeoutMs/1000;
        tv.tv_usec = (timeoutMs%1000)*1000;
        ptv = &tv;
    }
    
    ret = select(m_sockfd + 1, NULL, &writefds, NULL, ptv);
    if (0==ret)
    {
        //TRACE_ERR_CLASS("send timeout\n");
        return STATUS_ERROR;
    }
	else if(ret<0)
	{
		TRACE_ERR_CLASS("select error:%s.\n",ERROR_STRING);
        return STATUS_ERROR;
	}
		
    /* 检查fd是否可写 */
    if (!FD_ISSET(m_sockfd, &writefds))
    {
        TRACE_ERR_CLASS("writefds error.\n");
        return STATUS_ERROR;
    }

    /* 防止在socket关闭后,write会产生SIGPIPE信号导致进程退出 */
    signal(SIGPIPE, SIG_IGN);

    struct sockaddr_in peerSockAddr;
    peerSockAddr.sin_family = AF_INET;
    peerSockAddr.sin_port = htons(m_peerPort);
    peerSockAddr.sin_addr.s_addr = inet_addr(m_peerAddr.c_str());

    //TRACE_DBG_CLASS("UDP sendto(%s:%d)\n",m_peerAddr.c_str(),m_peerPort);
    int sendLen = sendto(m_sockfd, data, len, 0,
                           (struct sockaddr *)&peerSockAddr,
                           sizeof(peerSockAddr));
    if (sendLen < 0)
    {
        TRACE_ERR_CLASS("sockfd(%d) write error:%s\n", m_sockfd, ERROR_STRING);
        return STATUS_ERROR;
    }

    return sendLen;
}

TcpSocket::TcpSocket()
{
}
TcpSocket::~TcpSocket()
{
}
/**
 *  \brief  打开TCP socket
 *  \param  void
 *  \return 成功返回true,失败返回false
 *  \note   none
 */
bool TcpSocket::open()
{
    if (m_sockfd < 0)
    {
        m_sockfd = socket(PF_INET, SOCK_STREAM, 0);
        if (m_sockfd < 0)
        {
            TRACE_ERR_CLASS("open socket error:%s\n", ERROR_STRING);
            return false;
        }
    }

    int on = 1;
    if(setsockopt(m_sockfd, SOL_SOCKET,SO_REUSEADDR, &on, sizeof(on))<0)
    {
        TRACE_ERR_CLASS("setsockopt error:%s\n", ERROR_STRING);
        return false;
    }
    return true;
}

/**
 *  \brief  关闭TCP socket
 *  \param  void
 *  \return 成功返回true,失败返回false
 *  \note   none
 */
bool TcpSocket::close()
{
    return Socket::close();
}

/**
 *  \brief  TCP socket连接远端
 *  \param  port 对端端口
 *  \param  ipaddr 对端IP地址
 *  \return 成功返回接收的数据长度,失败返回STATUS_ERROR
 *  \note   none
 */
bool TcpSocket::connectToHost(uint16 port, std::string ipaddr)
{
    int ret;
	struct sockaddr_in peerSockAddr;
    bzero(&peerSockAddr, sizeof(peerSockAddr));
    peerSockAddr.sin_family = AF_INET;
    peerSockAddr.sin_port = htons(port);
    if (ipaddr.empty())
    {
        TRACE_ERR_CLASS("peer ip addr not set\n");
        return false;
    }
    else
    {
        peerSockAddr.sin_addr.s_addr = inet_addr(ipaddr.c_str());
    }

    /*开始连接服务器connect*/
    TRACE_REL_CLASS("connect to %s:%d\n", inet_ntoa(peerSockAddr.sin_addr), ntohs(peerSockAddr.sin_port));
    int constatus = ::connect(m_sockfd, (struct sockaddr *)&peerSockAddr, sizeof(peerSockAddr));
    if (0 == constatus) //连接正常
    {
        struct timeval tv;
        fd_set writefds;

        tv.tv_sec = 5;
        tv.tv_usec = 0;

        FD_ZERO(&writefds);
        FD_SET(m_sockfd, &writefds);

        ret = select(m_sockfd + 1, NULL, &writefds, NULL, &tv);
        if (0 == ret)
        {
            //TRACE_ERR_CLASS("select timeout.\n");
            return false;
        }
		else if (ret < 0)
        {
            TRACE_ERR_CLASS("select error:%s.\n",ERROR_STRING);
            return false;
        }

        if (!FD_ISSET(m_sockfd, &writefds))
        {
            TRACE_ERR_CLASS("socket fd error.\n");
            return false;
        }
        TRACE_REL_CLASS("=========TcpSocket connect success.\n");
        return true;
    }
    else
    {
        TRACE_ERR_CLASS("connect error:%s.\n", ERROR_STRING);
        if (errno != EINPROGRESS)
        {
            TRACE_ERR_CLASS("connect error.\n");
        }
    }
    return false;
}

/**
 *  \brief  TCP socket监听连接
 *  \param  maxpend 最大挂起连接数
 *  \return 成功返回true,失败返回false
 *  \note   none
 */
bool TcpSocket::listenConnection(int maxpending)
{
    int ret;
    ret = ::listen(m_sockfd, maxpending);
    if (ret < 0)
    {
        TRACE_ERR_CLASS("listen error:%s.\n", ERROR_STRING);
        return false;
    }
    return true;
}

/**
 *  \brief  TCP socket接受连接
 *  \param  newsocket 接受的新连接
 *  \return 成功返回true,失败返回false
 *  \note   none
 */
bool TcpSocket::acceptConnection(TcpSocket& newsocket)
{
    int ret;
    struct sockaddr_in client_sockaddr;
    int addr_size = sizeof(struct sockaddr_in);
    ret = ::accept(m_sockfd, (struct sockaddr *)&client_sockaddr, (socklen_t *)&addr_size);
    if (ret < 0)
    {
        TRACE_ERR_CLASS("accept error:%s\n", ERROR_STRING);
        sleep(3);
        return false;
    }
    newsocket.m_sockfd = ret;

    TRACE_REL_CLASS("tcp connection from %s:%d\n", inet_ntoa(client_sockaddr.sin_addr), ntohs(client_sockaddr.sin_port));
    return true;
}


LocalTcpSocket::LocalTcpSocket()
{
}

LocalTcpSocket::~LocalTcpSocket()
{
}

bool LocalTcpSocket::open()
{
    if (m_sockfd < 0)
    {
        m_sockfd = socket(PF_LOCAL, SOCK_STREAM, 0);
        if (m_sockfd < 0)
        {
            TRACE_ERR_CLASS("open socket error:%s\n", ERROR_STRING);
            return false;
        }
    }
    return true;
}

/**
 *  \brief  关闭 local socket
 *  \param  void
 *  \return 成功返回true,失败返回false
 *  \note   none
 */
bool LocalTcpSocket::close()
{
    return Socket::close();
}

/**
 *  \brief  绑定socket到指定本地socket
 *  \param  localName   本地socket名称 
 *  \return 成功返回true,失败返回false
 *  \note   none
 */
bool LocalTcpSocket::bindLocal(std::string localName)
{
    int ret = -1;
    if (m_sockfd < 0)
    {
        TRACE_ERR_CLASS("socket is not open\n");
        return false;
    }
    bzero(&m_sockaddr, sizeof(m_sockaddr)); 
    m_sockaddr.sun_family = AF_LOCAL;
    /* 这里socket命名有两种,一种是有名的(在文件系统中实际存在),一种是无名的(系统全局名称),无名的sun_path[0]必须为0 */
    m_sockaddr.sun_path[0]=0;
    strcpy(m_sockaddr.sun_path+1,localName.c_str());

    /*地址与socket绑定bind*/
    ret = ::bind(m_sockfd, (struct sockaddr *)&m_sockaddr, sizeof(m_sockaddr));
    if (ret < 0)
    {
        TRACE_ERR_CLASS("bind error:%s.\n",ERROR_STRING);
        return false;
    }
    return true;
}

/**
 *  \brief  连接本地socket
 *  \param  localName   本地socket名称 
 *  \return 成功返回true,失败返回false
 *  \note   none
 */
bool LocalTcpSocket::connectLocal(std::string localName)
{
    int ret;
    bzero(&m_sockaddr, sizeof(m_sockaddr)); 
    m_sockaddr.sun_family = AF_LOCAL;
    /* 这里socket命名有两种,一种是有名的(在文件系统中实际存在),一种是无名的(系统全局名称),无名的sun_path[0]必须为0 */
    m_sockaddr.sun_path[0]=0;
    strcpy(m_sockaddr.sun_path+1,localName.c_str());

    /*开始连接服务器connect*/
    TRACE_REL_CLASS("connect to %s\n", localName.c_str());
    int constatus = ::connect(m_sockfd, (struct sockaddr *)&m_sockaddr, sizeof(m_sockaddr));
    if (0 == constatus) //连接正常
    {
        struct timeval tv;
        fd_set writefds;

        tv.tv_sec = 5;
        tv.tv_usec = 0;

        FD_ZERO(&writefds);
        FD_SET(m_sockfd, &writefds);

        ret = select(m_sockfd + 1, NULL, &writefds, NULL, &tv);
        if (0 == ret)
        {
            //TRACE_ERR_CLASS("select timeout.\n");
            return false;
        }
		else if (ret < 0)
        {
            TRACE_ERR_CLASS("select error:%s.\n",ERROR_STRING);
            return false;
        }

        if (!FD_ISSET(m_sockfd, &writefds))
        {
            TRACE_ERR_CLASS("socket fd error.\n");
            return false;
        }
        TRACE_REL_CLASS("Local Socket connect success.\n");
        return true;
    }
    else
    {
        TRACE_ERR_CLASS("connect error:%s.\n", ERROR_STRING);
        if (errno != EINPROGRESS)
        {
            TRACE_ERR_CLASS("connect error.\n");
        }
    }
    return false;
}

/**
 *  \brief  TCP socket监听连接
 *  \param  maxpend 最大挂起连接数
 *  \return 成功返回true,失败返回false
 *  \note   none
 */
bool LocalTcpSocket::listenConnection(int maxpending)
{
    int ret;
    ret = ::listen(m_sockfd, maxpending);
    if (ret < 0)
    {
        TRACE_ERR_CLASS("listen error:%s.\n", ERROR_STRING);
        return false;
    }
    return true;
}

/**
 *  \brief  LocalTcpSocket接受连接
 *  \param  newsocket 接受的新连接
 *  \return 成功返回true,失败返回false
 *  \note   none
 */
bool LocalTcpSocket::acceptConnection(LocalTcpSocket& newsocket)
{
    int ret;
    struct sockaddr_un client_sockaddr;
    int addr_size = sizeof(client_sockaddr);
    ret = ::accept(m_sockfd, (struct sockaddr *)&client_sockaddr, (socklen_t *)&addr_size);
    if (ret < 0)
    {
        TRACE_ERR_CLASS("accept error:%s\n", ERROR_STRING);
        sleep(3);
        return false;
    }
    newsocket.m_sockfd = ret; 
    TRACE_REL_CLASS("Local socket connection from %s.\n", m_sockaddr.sun_path+1); 
    return true;
}


TcpServer::TcpServer()
{
}

TcpServer::~TcpServer()
{
    int clientNum = m_clientCollection.size();
    for (int i=0; i<clientNum; i++) 
    {
        m_clientCollection[i]->close();
        DEL_OBJ(m_clientCollection[i]);
    }
    m_serverSocket.close();    
}

/**
 *  \brief  初始化服务器
 *  \param  serverPort 服务器端口
 *  \param  maxConAllows 服务器最多支持挂起连接数(仅TCP时有效)
 *  \return 成功返回STATUS_OK,失败返回STATUS_ERROR
 *  \note   none
 */
bool TcpServer::initServer(uint16 serverPort,std::string serverIP,int maxPendings)
{
    if(!m_serverSocket.open())
    {
        return false;
    }
    if (!m_serverSocket.bind(serverPort,serverIP))
    {
        return false;
    }

    if (!m_serverSocket.listenConnection(maxPendings))
    {
        return false;
    }
    return true;
}

/**
 *  \brief  启动服务器
 *  \param  void
 *  \return 成功返回true,失败返回false
 *  \note   none
 */
bool TcpServer::startServer()
{
    m_mainThread.start(this);
    return true;
}
/**
 *  \brief  停止服务器
 *  \param  void
 *  \return 成功返回true,失败返回false
 *  \note   none
 */
bool TcpServer::stopServer()
{
    m_mainThread.cancel();
    return true;
}

void TcpServer::run()
{
    TcpSocket* client=NULL;
    while(1)
    {
        if (client==NULL) 
        {
            client = NEW_OBJ TcpSocket();
        }
        if(!m_serverSocket.acceptConnection(*client))
        {
            continue;
        }
        else
        {
            m_clientCollection.push_back((Socket*)client);
            onNewConnection((Socket*)client);
            client=NULL;
        }
    }
}


LocalTcpServer::LocalTcpServer()
{
}

LocalTcpServer::~LocalTcpServer()
{
}

/**
 *  \brief  初始化服务器
 *  \param  serverName 服务器端socket名称
 *  \param  maxConAllows 服务器最多支持挂起连接数(仅TCP时有效)
 *  \return 成功返回STATUS_OK,失败返回STATUS_ERROR
 *  \note   none
 */
bool LocalTcpServer::initServer(std::string serverName,int maxPendings)
{
    if(!m_serverSocket.open())
    {
        return false;
    }
    if (!m_serverSocket.bindLocal(serverName)) 
    {
        return false;
    }
    else
    {
        TRACE_REL_CLASS("bind ok:%s.\n",serverName.c_str());
    }

    if (!m_serverSocket.listenConnection(maxPendings))
    {
        return false;
    }
    
    return true;
}

void LocalTcpServer::run()
{
    LocalTcpSocket* client=NULL;
    while(1)
    {
        if (client==NULL) 
        {
            client = NEW_OBJ LocalTcpSocket();
        }
        if(!m_serverSocket.acceptConnection(*client))
        {
            continue;
        }
        else
        {
            m_clientCollection.push_back((Socket*)client);
            onNewConnection((Socket*)client);
            client=NULL;
        }
    }
}
